/**
 * CPAR TOOLKIT - Compiler and Runtime for CPAR
 * Copyright (C) 2012 CPAR TOOLKIT Project Developers
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include <windows.h>
#include "cpar.h"

static HANDLE MainHeap = INVALID_HANDLE_VALUE;

typedef struct CPARListenerEntry
{
  CPARAllocatorListener listener;
  void                  *data;
}CPARListenerEntry;

struct CPARAllocator
{
  HANDLE            heap;
  CPARPointerArray  *destroyListeners;
  BOOL              destroying;
};

long CPARAllocatorInit()
{
  MainHeap = GetProcessHeap();
  return MainHeap != INVALID_HANDLE_VALUE;
}

long CPARAllocatorCreate( CPARAllocator **allocator )
{
  CPARAllocator *out;
  long          r;

  out = NULL;
  r   = 0;

  out = (CPARAllocator*)HeapAlloc(MainHeap, 0, sizeof(CPARAllocator));
  if(NULL == out)
    return 0;
  
  ZeroMemory(out,sizeof(CPARAllocator));

  out->heap = HeapCreate(0, 0, 0);
  if(INVALID_HANDLE_VALUE == out->heap)
  {
    HeapFree(MainHeap,0,(void*)out);
    return -1;
  }

  r = CPARPointerArrayCreate(out, &(out->destroyListeners), 5, 5);
  if(r)
  {
    HeapFree(MainHeap,0,(void*)out);
    return r;
  }

  out->destroying = FALSE;

  *allocator = out;
  return 0;
}

void CPARAllocatorDestroy( CPARAllocator *allocator )
{
  CPARListenerEntry **listeners;
  long              listenersCount;
  long              idx;

  allocator->destroying = TRUE;

  listeners = (CPARListenerEntry**) CPARPointerArrayGetData(allocator->destroyListeners);
  listenersCount = CPARPointerArrayCount(allocator->destroyListeners);
  for(idx = 0 ; idx < listenersCount;idx++)
  {
    listeners[idx]->listener(allocator,listeners[idx]->data);
  }

  HeapDestroy(allocator->heap);
  HeapFree(MainHeap,0,(void*)allocator);
}

void * CPARAllocatorAlloc( CPARAllocator *allocator, size_t size )
{
  return HeapAlloc(allocator->heap, 0, size);
}

void CPARAllocatorFree( CPARAllocator *allocator, void *mem )
{
  HeapFree(allocator->heap, 0, mem);
}

long CPARAllocatorDestroyListenerAdd( CPARAllocator *allocator, CPARAllocatorListener listener, void *data)
{
  long              idx;
  long              r;
  CPARListenerEntry *entry;

  entry = NULL;
  r     = 0;
  idx   = 0;

  entry = CPARAllocatorAlloc(allocator, sizeof(CPARListenerEntry));
  if(NULL == entry)
    return -1;

  entry->data = data;
  entry->listener = listener;

  r = CPARPointerArrayAdd(allocator->destroyListeners, entry, &idx );
  if(r)
  {
    CPARAllocatorFree(allocator, entry);
    return r;
  }

  return idx;
}

void CPARAllocatorDestroyListenerRemove( CPARAllocator *allocator, long listenerId )
{

  CPARPointerArrayRemove(allocator->destroyListeners, listenerId);
}

